home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
admin
/
linuxcon.000
/
linuxcon
/
linuxconf-1.6
/
userconf
/
users.c
< prev
Wrap
C/C++ Source or Header
|
1996-07-20
|
8KB
|
401 lines
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
#include <sys/stat.h>
#include "../xconf/xconf.h"
#include "../paths.h"
#include "internal.h"
#include "userconf.h"
#include "userconf.m"
/* #Specification: userconf / etc/passwd
/etc/passwd is the user database. Its permission flags are
always set to 0644 when rewritten.
*/
#define ETC_PTMP "/etc/ptmp"
static USERCONF_HELP_FILE help_users ("users");
static CONFIG_FILE f_passwd (ETC_PASSWD,help_users,CONFIGF_MANAGED
,"root","root",0644);
PUBLIC USERS::USERS()
{
/* #Specification: /etc/passwd / strategy
/etc/passwd is read "by hand" instead of using getpwent() to avoid
getting all those NIS entries. This is done when editing local
user account.
*/
FILE *fin = f_passwd.fopen ("r");
if (fin != NULL){
char line[1000];
while (fgets(line,sizeof(line)-1,fin)!=NULL){
strip_end (line);
if (line[0] != '\0'){
add (new USER(line));
}
}
fclose (fin);
}
shadows = NULL;
if (shadow_exist()) shadows = new SHADOWS;
rstmodified();
}
PUBLIC USERS::~USERS()
{
delete shadows;
}
/*
Get one USER specification of the table or NULL
*/
PUBLIC USER *USERS::getitem(int no)
{
return (USER*)ARRAY::getitem(no);
}
/*
Get one USER specification of the table or NULL from his login name
*/
PUBLIC USER *USERS::getitem(const char *name)
{
USER *ret = NULL;
int nbu = getnb();
for (int i=0; i<nbu; i++){
USER *usr = getitem(i);
if (strcmp(usr->getname(),name)==0){
ret = usr;
break;
}
}
return ret;
}
/*
Get one SHADOW specification of the table or NULL from his login name
*/
PUBLIC SHADOW *USERS::getshadow(USER *usr)
{
SHADOW *ret = NULL;
if (shadows != NULL) ret = shadows->getitem(usr->getname());
return ret;
}
PUBLIC void USERS::addshadow (SHADOW *shadow)
{
shadows->add (shadow);
}
/*
Get one USER specification of the table or NULL from his UID
*/
PUBLIC USER *USERS::getfromuid(int uid)
{
USER *ret = NULL;
int nbu = getnb();
for (int i=0; i<nbu; i++){
USER *usr = getitem(i);
if (usr->getuid() == uid){
ret = usr;
break;
}
}
return ret;
}
/*
Get one unused User ID base of the group name.
This function try to organise user id group wize, allocating 500
entry per group.
*/
PUBLIC int USERS::getnewuid(int gid)
{
/* #Specification: userconf / automatic allocaion of uid
We multiply gid by 500. From there we search in all
user id and allocate the first uid in the range.
We don't allocate into holes (unused uid between used one)
to avoid uid reuse (and a security hole).
*/
int base = gid * 500;
int maxu = base + 500;
int ret = base;
int nbu = getnb();
for (int i=0; i<nbu; i++){
USER *usr = getitem(i);
int uid = usr->getuid();
if (uid >= base && uid < maxu){
if (uid >= ret) ret = uid + 1;
}
}
return ret;
}
/*
Write the /etc/passwd file with proper locking
*/
PUBLIC int USERS::write()
{
int ret = -1;
sortbygid();
FILE *fout = f_passwd.fopen (ETC_PTMP,"w");
if (fout != NULL){
int nbu = getnb();
for (int i=0; i<nbu; i++){
getitem(i)->write(fout);
}
fclose(fout);
unlink(ETC_PASSWD ".OLD");
link(ETC_PASSWD, ETC_PASSWD ".OLD");
unlink(ETC_PASSWD);
link(ETC_PTMP, ETC_PASSWD);
unlink(ETC_PTMP);
if (shadows != NULL) shadows->write();
ret = 0;
}
return ret;
}
/*
Select one user from the list.
May return NULL if no valid selection was done (escape). See code.
*/
PUBLIC USER *USERS::select(
USER *like, // Used to select which user to pick.
// the function USER::islike() is called for
// each.
int may_add, // Set the delete and add button
MENU_STATUS &code,
int &choice) // Will contain the selection. Not so useful
// but help for the reentrancy of the list
// (It reedit on the last item selected).
{
int nbu = getnb();
sortbyname();
/* #Specification: userconf / user account / root bin ...
Some special account are simply left out of the configuration
menu. These account are never edited. They make the list larger
for no reason.
Also account with special shells are not shown. This include
accounts like uucp and slip. Theu are show in a separate menu.
The same functionnality is used to edit those accounts, but
the editition is trigerred from different menus.
*/
DIALOG dia;
for (int i=0; i<nbu; i++){
USER *usr = getitem(i);
if (usr->is_like(like)){
dia.new_menuitem (usr->getname(),usr->getgecos());
}
}
if (may_add){
dia.addwhat (MSG_R(I_TOADD));
}
code = dia.editmenu (MSG_U(T_USERACCT,"Users accounts")
,may_add
? MSG_U(I_CANEDIT,"You can edit, add, or delete users")
: MSG_U(I_SELECT,"You must select one of those users")
,help_users
,choice,0);
USER *ret = NULL;
// Locate the selected user in the list, given that not all
// user where displayed.
int nou = 0;
for (int j=0; j<nbu; j++){
USER *usr = getitem(j);
if (usr->is_like(like)){
if (nou == choice){
ret = usr;
break;
}
nou++;
}
}
return ret;
}
/*
Add one new user
Return -1 if the user was not added.
*/
PUBLIC int USERS::addone (
USER *special,
const char *name, // Proposed login name
GROUPS &groups)
{
int ret = -1;
USER *user = new USER;
user->setlike (special);
user->setname (name);
ret = user->edit(*this,groups,1);
if (ret==0){
add (user);
write ();
}else{
delete user;
}
return ret;
}
/*
General edition (addition/deletion/correction) of /etc/passwd
*/
PUBLIC int USERS::edit(
USER *special) // Template for user creation
// and selection.
{
int ret = -1;
int choice = 0;
GROUPS groups;
while (1){
MENU_STATUS code;
USER *usr = select (special,1,code,choice);
if (code == MENU_ESCAPE || code == MENU_QUIT){
break;
}else if (code == MENU_OK){
if (usr != NULL){
int status = usr->edit(*this,groups,0);
if (status != -1){
if (status == 1) remove_del (usr);
write();
ret = 0;
}
}
}else if (perm_rootaccess(MSG_U(P_USERDB
,"to maintain the user database"))){
if (code == MENU_ADD){
addone (special,NULL,groups);
}
}
}
return ret;
}
static int cmpbyname (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2)
{
USER *g1 = (USER*) o1;
USER *g2 = (USER*) o2;
return strcmp(g1->getname(),g2->getname());
}
/*
Sort the array of group by name
*/
PUBLIC void USERS::sortbyname()
{
sort (cmpbyname);
}
static int cmpbygid (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2)
{
USER *g1 = (USER*) o1;
USER *g2 = (USER*) o2;
int ret = g1->getgid() - g2->getgid();
if (ret == 0){
ret = strcmp(g1->getname(),g2->getname());
}
return ret;
}
/*
Sort the array of group by gid, and name
*/
PUBLIC void USERS::sortbygid()
{
sort (cmpbygid);
}
/*
Edition of users password.
Return 0 if at least one change was done.
*/
PUBLIC int USERS::editpass(
USER *special) // see USERS::select()
{
int ret = -1;
int choice = 0;
while (1){
MENU_STATUS code;
USER *usr = select (special,0,code,choice);
if (code == MENU_ESCAPE || code == MENU_QUIT){
break;
}else{
SHADOW *shadow = getshadow (usr);
if (usr->editpass(1,shadow) != -1){
write();
ret = 0;
}
}
}
return ret;
}
/*
General edition of users account and special account
See USERS::edit()
*/
void users_edit(
USER *special) // Template for a special account.
// Or NULL.
{
USERS users;
users.edit(special);
}
/*
Add one new special user
*/
void users_addone(
const char *name,
const char *group) // Which group to use or NULL.
{
if (perm_rootaccess(MSG_R(P_USERDB))){
USER *special;
if (special_init (group,special) != -1){
USERS users;
GROUPS groups;
users.addone(special,name,groups);
}
delete special;
}
}
/*
Return != 0 if a user account exist.
*/
int user_exist (const char *name)
{
return getpwnam(name)!=NULL;
}
/*
Edit one user spec.
If the user does not exist, ask if we want to create it.
*/
void users_editone(
const char *name,
const char *group) // Group to use (or NULL) if the user
// is created
{
USERS users;
if (perm_rootaccess(MSG_R(P_USERDB))){
USER *user = users.getitem(name);
if (user == NULL){
char buf[300];
sprintf (buf,MSG_U(I_USERCREATE,"User account %s does not exist\n"
"Do you want to create it"),name);
if (xconf_yesno(MSG_U(Q_USERCREATE,"Account creation")
,buf,help_users)==MENU_YES){
users_addone (name,group);
}
}else{
GROUPS groups;
if (user->edit(users,groups,0)!=-1) users.write();
}
}
}
#ifdef TEST
int main (int argc, char *argv[])
{
users_edit(NULL);
users_edit("-");
users_edit("/usr/lib/uucp/uucico");
}
#endif